﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Duckov.Modding;
using UnityEngine;
using Debug = UnityEngine.Debug;

// ReSharper disable CheckNamespace

public static class ModSettingAPI
{
    private const string ADD_DROP_DOWN_LIST = "AddDropDownList";
    private const string ADD_SLIDER = "AddSlider";
    private const string ADD_TOGGLE = "AddToggle";
    private const string ADD_KEYBINDING = "AddKeybinding";
    private const string GET_VALUE = "GetValue";
    private const string SET_VALUE = "SetValue";
    private const string REMOVE_UI = "RemoveUI";
    private const string REMOVE_MOD = "RemoveMod";
    private const string ADD_INPUT = "AddInput";
    private const string HAS_CONFIG = "HasConfig";
    private const string GET_SAVED_VALUE = "GetSavedValue";
    private const string ADD_KEYBINDING_WITH_DEFAULT = "AddKeybindingWithDefault";
    private const string ADD_BUTTON = "AddButton";

    private const string ADD_GROUP = "AddGroup";

    // private static float _version = 0.4f;
    private static readonly Version Version = new Version(0, 4, 0);
    private const string MOD_NAME = "ModSetting";
    private const string TYPE_NAME = "ModSetting.ModBehaviour";
    private static Type? _modBehaviour;
    private static ModInfo _modInfo;

    public static bool IsInit { get; private set; }

    // 缓存委托避免重复反射
    private static readonly Dictionary<string, Delegate> MethodCache = new Dictionary<string, Delegate>();

    private static readonly string[] MethodNames =
    {
        ADD_DROP_DOWN_LIST,
        ADD_SLIDER,
        ADD_TOGGLE,
        ADD_KEYBINDING,
        GET_VALUE,
        SET_VALUE,
        REMOVE_UI,
        REMOVE_MOD,
        ADD_INPUT,
        HAS_CONFIG,
        GET_SAVED_VALUE,
        ADD_KEYBINDING_WITH_DEFAULT,
        ADD_BUTTON,
        ADD_GROUP
    };

    /// <summary>
    /// 初始化API
    /// </summary>
    /// <param name="modInfo">mod信息</param>
    /// <returns>是否成功初始化</returns>
    public static bool Init(ModInfo modInfo)
    {
        if (IsInit) return true;
        if (modInfo.name == MOD_NAME)
        {
            Debug.LogError("初始化失败，不能使用ModSetting的info进行初始化");
            return false;
        }

        _modInfo = modInfo;
        _modBehaviour = FindTypeInAssemblies(TYPE_NAME);
        if (_modBehaviour == null) return false;
        VersionAvailable();
        foreach (var methodName in MethodNames)
        {
            var methodInfos = _modBehaviour.GetMethods(BindingFlags.Public | BindingFlags.Static)
                .Where(m => m.Name == methodName)
                .ToArray();
            if (methodInfos.Length != 0) continue;
            Debug.LogError($"{methodName}方法找不到");
            return false;
        }

        IsInit = true;
        return true;
    }

    /// <summary>
    /// 添加一个下拉列表控件
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="description">描述文本</param>
    /// <param name="options">选项列表</param>
    /// <param name="defaultValue">当前值</param>
    /// <param name="onValueChange">值改变时的回调函数</param>
    /// <returns></returns>
    public static bool AddDropdownList(string key, string description,
        List<string> options, string defaultValue, Action<string> onValueChange)
    {
        if (!Available(key)) return false;
        var delegateType = typeof(Action<ModInfo, string, string, List<string>, string, Action<string>>);
        return InvokeMethod(ADD_DROP_DOWN_LIST,
            ADD_DROP_DOWN_LIST,
            new object[] { _modInfo, key, description, options, defaultValue, onValueChange },
            delegateType);
    }

    /// <summary>
    /// 添加一个浮点数滑块控件
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="description">描述文本</param>
    /// <param name="defaultValue">当前值</param>
    /// <param name="sliderRange">滑块范围</param>
    /// <param name="onValueChange">值改变时的回调函数</param>
    /// <param name="decimalPlaces">小数位数</param>
    /// <param name="characterLimit">输入字符限制</param>
    /// <returns></returns>
    public static bool AddSlider(string key, string description,
        float defaultValue, Vector2 sliderRange, Action<float> onValueChange, int decimalPlaces = 1,
        int characterLimit = 5)
    {
        if (!Available(key)) return false;
        Type[] paramTypes =
        {
            typeof(ModInfo), typeof(string), typeof(string),
            typeof(float), typeof(Vector2), typeof(Action<float>), typeof(int), typeof(int)
        };
        var delegateType = typeof(Action<ModInfo, string, string, float, Vector2, Action<float>, int, int>);
        return InvokeMethod(ADD_SLIDER + "Float",
            ADD_SLIDER,
            new object[]
                { _modInfo, key, description, defaultValue, sliderRange, onValueChange, decimalPlaces, characterLimit },
            delegateType,
            paramTypes);
    }

    /// <summary>
    /// 添加一个整数滑块控件
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="description">描述文本</param>
    /// <param name="defaultValue">当前值</param>
    /// <param name="minValue">最小值</param>
    /// <param name="maxValue">最大值</param>
    /// <param name="onValueChange">值改变时的回调函数</param>
    /// <param name="characterLimit">输入字符限制</param>
    /// <returns></returns>
    public static bool AddSlider(string key, string description,
        int defaultValue, int minValue, int maxValue, Action<int> onValueChange, int characterLimit = 5)
    {
        if (!Available(key)) return false;
        Type[] paramTypes =
        {
            typeof(ModInfo), typeof(string), typeof(string),
            typeof(int), typeof(int), typeof(int), typeof(Action<int>), typeof(int)
        };
        var delegateType = typeof(Action<ModInfo, string, string, int, int, int, Action<int>, int>);
        return InvokeMethod(ADD_SLIDER + "Int", ADD_SLIDER,
            new object[]
                { _modInfo, key, description, defaultValue, minValue, maxValue, onValueChange, characterLimit },
            delegateType,
            paramTypes);
    }

    /// <summary>
    /// 添加一个开关控件
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="description">描述文本</param>
    /// <param name="enable">当前值</param>
    /// <param name="onValueChange">值改变时的回调函数</param>
    /// <returns></returns>
    public static bool AddToggle(string key, string description,
        bool enable, Action<bool> onValueChange)
    {
        if (!Available(key)) return false;
        var delegateType = typeof(Action<ModInfo, string, string, bool, Action<bool>>);
        return InvokeMethod(ADD_TOGGLE,
            ADD_TOGGLE,
            new object[] { _modInfo, key, description, enable, onValueChange },
            delegateType);
    }

    /// <summary>
    /// 添加一个按键绑定控件，默认值None
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="description">描述文本</param>
    /// <param name="keyCode">当前值</param>
    /// <param name="onValueChange">值改变时的回调函数</param>
    /// <returns></returns>
    public static bool AddKeybinding(string key, string description,
        KeyCode keyCode, Action<KeyCode> onValueChange)
    {
        if (!Available(key)) return false;
        return InvokeMethod(ADD_KEYBINDING,
            ADD_KEYBINDING,
            new object[] { _modInfo, key, description, keyCode, onValueChange },
            typeof(Action<ModInfo, string, string, KeyCode, Action<KeyCode>>));
    }

    /// <summary>
    /// 添加一个带默认值的按键绑定控件
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="description">描述文本</param>
    /// <param name="keyCode">当前值</param>
    /// <param name="defaultKeyCode">默认值</param>
    /// <param name="onValueChange">值改变时的回调函数</param>
    /// <returns></returns>
    public static bool AddKeybinding(string key, string description,
        KeyCode keyCode, KeyCode defaultKeyCode, Action<KeyCode> onValueChange)
    {
        if (!Available(key)) return false;
        return InvokeMethod(ADD_KEYBINDING_WITH_DEFAULT,
            ADD_KEYBINDING_WITH_DEFAULT,
            new object[] { _modInfo, key, description, keyCode, defaultKeyCode, onValueChange },
            typeof(Action<ModInfo, string, string, KeyCode, KeyCode, Action<KeyCode>>));
    }

    /// <summary>
    /// 添加一个输入框控件
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="description">描述文本</param>
    /// <param name="defaultValue">当前值</param>
    /// <param name="characterLimit">输入字符限制</param>
    /// <param name="onValueChange">值改变时的回调函数</param>
    /// <returns></returns>
    public static bool AddInput(string key, string description,
        string defaultValue, int characterLimit, Action<string> onValueChange)
    {
        if (!Available(key)) return false;
        return InvokeMethod(ADD_INPUT,
            ADD_INPUT,
            new object[] { _modInfo, key, description, defaultValue, characterLimit, onValueChange },
            typeof(Action<ModInfo, string, string, string, int, Action<string>>));
    }

    /// <summary>
    /// 添加一个按钮控件
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="description">描述文本</param>
    /// <param name="buttonText">按钮文本</param>
    /// <param name="onClickButton">点击时的回调函数</param>
    /// <returns></returns>
    public static bool AddButton(string key, string description,
        string buttonText, Action onClickButton)
    {
        if (!Available(key)) return false;
        return InvokeMethod(ADD_BUTTON,
            ADD_BUTTON,
            new object[] { _modInfo, key, description, buttonText, onClickButton },
            typeof(Action<ModInfo, string, string, string, Action>));
    }

    /// <summary>
    /// 添加一个分组控件，用于将多个控件组织在一起
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="description">描述文本</param>
    /// <param name="keys">包含的控件键列表(暂不支持嵌套Group)</param>
    /// <param name="scale">缩放比例(相对于mod标题)，最大0.9f</param>
    /// <param name="topInsert">是否插入到顶部</param>
    /// <param name="open">是否默认展开</param>
    /// <returns></returns>
    public static bool AddGroup(string key, string description, List<string> keys,
        float scale = 0.7f, bool topInsert = false, bool open = false)
    {
        if (!Available(key)) return false;
        return InvokeMethod(ADD_GROUP,
            ADD_GROUP,
            new object[] { _modInfo, key, description, keys, scale, topInsert, open },
            typeof(Action<ModInfo, string, string, List<string>, float, bool, bool>));
    }

    /// <summary>
    /// 获取指定key的配置值
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="callback">回调函数返回结果</param>
    /// <typeparam name="T">值类型</typeparam>
    /// <returns></returns>
    public static bool GetValue<T>(string key, Action<T> callback)
    {
        if (!Available(key)) return false;
        var methodInfo = GetStaticPublicMethodInfo(GET_VALUE);
        if (methodInfo == null) return false;
        var genericMethod = methodInfo.MakeGenericMethod(typeof(T));
        genericMethod.Invoke(null, new object[] { _modInfo, key, callback });
        return true;
    }

    /// <summary>
    /// 设置指定key的配置值，单方面通知控件更新
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="value">设置值</param>
    /// <param name="callback">回调函数返回是否成功</param>
    /// <typeparam name="T">值类型</typeparam>
    /// <returns></returns>
    public static bool SetValue<T>(string key, T value, Action<bool> callback)
    {
        if (!Available(key)) return false;
        var methodInfo = GetStaticPublicMethodInfo(SET_VALUE);
        if (methodInfo == null) return false;
        var genericMethod = methodInfo.MakeGenericMethod(typeof(T));
        genericMethod.Invoke(null, new object[] { _modInfo, key, value, callback });
        return true;
    }

    /// <summary>
    /// 检查是否存在此mod的配置文件
    /// </summary>
    /// <returns></returns>
    public static bool HasConfig()
    {
        if (!Available()) return false;
        var methodInfo = GetStaticPublicMethodInfo(HAS_CONFIG);
        if (methodInfo == null) return false;
        return (bool)methodInfo.Invoke(null, new object[] { _modInfo });
    }

    /// <summary>
    /// 获取已保存的配置值
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="value">保存的值</param>
    /// <typeparam name="T">值类型</typeparam>
    /// <returns></returns>
    public static bool GetSavedValue<T>(string key, out T value)
    {
        value = default;
        if (!Available(key)) return false;
        var methodInfo = GetStaticPublicMethodInfo(GET_SAVED_VALUE);
        if (methodInfo == null) return false;
        var genericMethod = methodInfo.MakeGenericMethod(typeof(T));
        // 准备参数数组（注意：out 参数需要特殊处理）
        object[] parameters = { _modInfo, key, null };
        var result = (bool)genericMethod.Invoke(null, parameters);
        // 获取 out 参数的值
        value = (T)parameters[2];
        return result;
    }

    /// <summary>
    /// 移除指定键对应的UI控件
    /// </summary>
    /// <param name="key">控件key</param>
    /// <param name="callback">回调函数返回操作结果</param>
    /// <returns></returns>
    public static bool RemoveUI(string key, Action<bool> callback)
    {
        if (!Available(key)) return false;
        return InvokeMethod(REMOVE_UI,
            REMOVE_UI,
            new object[] { _modInfo, key, callback },
            typeof(Action<ModInfo, string, Action<bool>>));
    }

    /// <summary>
    /// 移除整个模组的UI配置,当禁用此mod时，ModSetting会自动移除相对应的UI，一般来说不需要调用，除非想要主动移除mod所有UI
    /// </summary>
    /// <param name="callback">回调函数返回操作结果</param>
    /// <returns></returns>
    public static bool RemoveMod(Action<bool> callback)
    {
        if (!Available()) return false;
        var delegateType = typeof(Action<ModInfo, Action<bool>>);
        return InvokeMethod(REMOVE_MOD, REMOVE_MOD, new object[] { _modInfo, callback }, delegateType);
    }

    private static bool Available()
    {
        return IsInit && _modInfo.displayName != null && _modInfo.name != null;
    }

    private static bool Available(string? key)
    {
        return IsInit && _modInfo.displayName != null && _modInfo.name != null && key != null;
    }

    private static bool VersionAvailable()
    {
        var versionField = _modBehaviour?.GetField("VERSION", BindingFlags.Public | BindingFlags.Static);
        if (versionField == null || versionField.FieldType != typeof(float)) return false;

        var modSettingVersion = (Version)versionField.GetValue(null);
        if (modSettingVersion == Version) return true;

        Debug.LogWarning($"警告:ModSetting的版本:{modSettingVersion} (API的版本:{Version}),新功能将无法使用");
        return false;
    }

    private static Type? FindTypeInAssemblies(string typeName)
    {
        Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
        foreach (var assembly in assemblies)
        {
            if (assembly.FullName.Contains(MOD_NAME))
            {
                Debug.Log($"找到{MOD_NAME}相关程序集: {assembly.FullName}");
            }

            var type = assembly.GetType(typeName);
            if (type != null) return type;
        }

        Debug.Log("找不到程序集");
        return null;
    }

    private static MethodInfo? GetStaticPublicMethodInfo(string methodName, Type[]? parameterTypes = null)
    {
        if (!IsInit) return null;
        const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Static;
        if (parameterTypes != null)
        {
            var methodInfos = _modBehaviour?.GetMethods(bindingFlags).Where(m => m.Name == methodName).ToArray();
            return methodInfos?.Where(methodInfo =>
            {
                var parameters = methodInfo.GetParameters();
                if (parameters.Length != parameterTypes.Length) return false;
                return !parameters.Where((t, i) => !IsParameterTypeMatch(t.ParameterType, parameterTypes[i])).Any();
            }).FirstOrDefault();
        }

        {
            var methodInfo = _modBehaviour?.GetMethod(methodName, bindingFlags);
            return methodInfo;
        }
    }

    private static bool IsParameterTypeMatch(Type parameterType, Type providedType)
    {
        // 精确匹配
        if (parameterType == providedType)
            return true;
        // 处理值类型和可空类型
        if (parameterType.IsValueType && Nullable.GetUnderlyingType(parameterType) == providedType)
            return true;
        // 处理继承关系
        if (parameterType.IsAssignableFrom(providedType))
            return true;
        return false;
    }

    private static bool InvokeMethod(string cacheKey, string methodName, object[] parameters, Type delegateType,
        Type[]? paramTypes = null)
    {
        if (!MethodCache.ContainsKey(cacheKey))
        {
            var method = GetStaticPublicMethodInfo(methodName, paramTypes);
            if (method == null) return false;
            // 创建委托
            MethodCache[cacheKey] = Delegate.CreateDelegate(delegateType, method);
        }

        try
        {
            MethodCache[cacheKey].DynamicInvoke(parameters);
            return true;
        }
        catch (Exception ex)
        {
            Debug.LogError($"委托调用{methodName}失败: {ex.Message}");
            return false;
        }
    }
}